﻿using Black.Minecraft.Editor.ViewModels.Core;
using Black.NBT;
using System;

namespace Black.Minecraft.Editor.ViewModels.DataModels
{
    /// <summary>
    /// ViewModel pour les informations du joueur
    /// </summary>
    public class PlayerInformationDataModel : BaseViewModel
    {
        #region Propriétés

        /// <summary>
        /// Obtient ou définit la faim du joueur (max 20)
        /// </summary>
        public int FoodLevel
        {
            get
            {
                return (((TagInt)this._data["foodLevel"]).Value);
            }
            set
            {
                TagInt item = ((TagInt)this._data["foodLevel"]);

                if (item.Value != value)
                {
                    item.Value = value;
                    this.OnPropertyChanged();
                    MainViewModel.Instance.IsModified = true;
                }
            }
        }

        /// <summary>
        /// Obtient ou définit le type de partie pour ce joueur en mode solo
        /// </summary>
        public SoloGameType GameType
        {
            get
            {
                return ((SoloGameType)((TagInt)this._data["playerGameType"]).Value);
            }
            set
            {
                SoloGameType item = (SoloGameType)((TagInt)this._data["playerGameType"]).Value;

                if (item != value)
                {
                    ((TagInt)this._data["playerGameType"]).Value = (int)value;
                    this.OnPropertyChanged();
                    this.ChangePlayerGameMode();
                }
            }
        }

        /// <summary>
        /// Obtient ou définit la coordonnée du joueur en X
        /// </summary>
        public double PosX
        {
            get
            {
                return (((TagDouble)((TagList)this._data["Pos"])[0]).Value);
            }
            set
            {
                TagDouble item = (TagDouble)((TagList)this._data["Pos"])[0];

                if (item.Value != value)
                {
                    item.Value = value;
                    this.OnPropertyChanged();
                    MainViewModel.Instance.IsModified = true;
                }
            }
        }

        /// <summary>
        /// Obtient ou définit la coordonnée du joueur en Y
        /// </summary>
        public double PosY
        {
            get
            {
                return (((TagDouble)((TagList)this._data["Pos"])[1]).Value);
            }
            set
            {
                TagDouble item = (TagDouble)((TagList)this._data["Pos"])[1];

                if (item.Value != value)
                {
                    item.Value = value;
                    this.OnPropertyChanged();
                    MainViewModel.Instance.IsModified = true;
                }
            }
        }

        /// <summary>
        /// Obtient ou définit la coordonnée du joueur en Z
        /// </summary>
        public double PosZ
        {
            get
            {
                return (((TagDouble)((TagList)this._data["Pos"])[2]).Value);
            }
            set
            {
                TagDouble item = (TagDouble)((TagList)this._data["Pos"])[2];

                if (item.Value != value)
                {
                    item.Value = value;
                    this.OnPropertyChanged();
                    MainViewModel.Instance.IsModified = true;
                }
            }
        }

        /// <summary>
        /// Obtient ou définit la coordonnée de spawn en X
        /// </summary>
        public int SpawnX
        {
            get
            {
                return (((TagInt)this._data["SpawnX"]).Value);
            }
            set
            {
                TagInt item = (TagInt)this._data["SpawnX"];

                if (item.Value != value)
                {
                    item.Value = value;
                    this.OnPropertyChanged();
                    MainViewModel.Instance.IsModified = true;
                }
            }
        }

        /// <summary>
        /// Obtient ou définit la coordonnée de spawn en Y
        /// </summary>
        public int SpawnY
        {
            get
            {
                return (((TagInt)this._data["SpawnY"]).Value);
            }
            set
            {
                TagInt item = (TagInt)this._data["SpawnY"];

                if (item.Value != value)
                {
                    item.Value = value;
                    this.OnPropertyChanged();
                    MainViewModel.Instance.IsModified = true;
                }
            }
        }

        /// <summary>
        /// Obtient ou définit la coordonnée de spawn en Z
        /// </summary>
        public int SpawnZ
        {
            get
            {
                return (((TagInt)this._data["SpawnZ"]).Value);
            }
            set
            {
                TagInt item = (TagInt)this._data["SpawnZ"];

                if (item.Value != value)
                {
                    item.Value = value;
                    this.OnPropertyChanged();
                    MainViewModel.Instance.IsModified = true;
                }
            }
        }

        /// <summary>
        /// Obtient ou définit l'expérence du joueur (max 40)
        /// </summary>
        public int XpLevel
        {
            get
            {
                return (((TagInt)this._data["XpLevel"]).Value);
            }
            set
            {
                TagInt item = ((TagInt)this._data["XpLevel"]);

                if (item.Value != value)
                {
                    item.Value = value;
                    this.OnPropertyChanged();
                    MainViewModel.Instance.IsModified = true;
                }
            }
        }

        #endregion

        #region Variables d'instances

        private TagCompound _data;

        #endregion

        #region Constructeurs

        /// <summary>
        /// Constructeur de la classe
        /// </summary>
        /// <param name="data">Source de donnée</param>
        public PlayerInformationDataModel(TagCompound data)
            : base()
        {
            // Vérification

            if (data == null)
                throw (new ArgumentNullException("data", "The player node is corrupted or does not exist."));

            // Afffectation des données

            this._data = data;

            // Vérification du point de spawn

            if (this._data["SpawnX"] == null)
                this._data.Items.Add(new TagInt("SpawnX"));

            if (this._data["SpawnY"] == null)
                this._data.Items.Add(new TagInt("SpawnY"));

            if (this._data["SpawnZ"] == null)
                this._data.Items.Add(new TagInt("SpawnZ"));
        }

        #endregion

        #region Fonctions publiques

        /// <summary>
        /// Retourne la source de donnée
        /// </summary>
        /// <returns>Source de donnée</returns>
        public TagCompound GetData()
        {
            return (this._data);
        }

        #endregion

        #region Fonctions privées

        /// <summary>
        /// Change le type de partie pour ce joueur
        /// </summary>
        private void ChangePlayerGameMode()
        {
            // Affectation des noeuds

            (this._data["OnGround"] as TagByte).Value = this.GameType == SoloGameType.Survival ? (byte)0 : (this._data["OnGround"] as TagByte).Value;
            (this._data["playerGameType"] as TagInt).Value = (int)this.GameType;

            TagCompound abilities = (this._data)["abilities"] as TagCompound;
            ((TagByte)abilities["flying"]).Value = this.GameType == SoloGameType.Survival ? (byte)0 : (byte)1;
            ((TagByte)abilities["mayfly"]).Value = this.GameType == SoloGameType.Survival ? (byte)0 : (byte)1;

            // Mode modification

            MainViewModel.Instance.IsModified = true;
        }

        #endregion
    }
}
